package com.apobates.jforum2.troll.forum.biz.impl.dao;

import com.apobates.jforum2.troll.forum.biz.dao.BoardStatsDao;
import com.apobates.jforum2.troll.forum.entity.BoardStats;
import com.apobates.jforum2.troll.regular.ForumActionEnum;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 *
 * @author xiaofanku
 * @since 20200513
 */
@Repository
public class BoardStatsDaoImpl implements BoardStatsDao{
    @PersistenceContext
    private EntityManager entityManager;
    private final static Logger logger = LoggerFactory.getLogger(BoardStatsDaoImpl.class);
    
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public Optional<Boolean> createStats(long boardId, int volumesId) {
        try {
            entityManager.persist(new BoardStats(boardId, volumesId));
            return Optional.of(true);
        } catch (Exception e) {
            if(logger.isDebugEnabled()){
                logger.debug(e.getMessage(), e);
            }
            return Optional.empty();
        }
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public Optional<Boolean> updateTopic(long boardId, String recentTopicTitle, long recentTopicId, LocalDateTime recentTopicDate, long recentTopicMemberId, String recentTopicMemberNickname) {
        try {
            int affect = entityManager
                    .createQuery("UPDATE BoardStats bs SET bs.topices = bs.topices + 1, bs.recentTopicTitle = ?1, bs.recentTopicId = ?2, bs.recentTopicDate = ?3, bs.recentTopicMemberId = ?4, bs.recentTopicMemberNickname = ?5, bs.updateDate = ?6 WHERE bs.boardId = ?7")
                    .setParameter(1, recentTopicTitle)
                    .setParameter(2, recentTopicId)
                    .setParameter(3, recentTopicDate)
                    .setParameter(4, recentTopicMemberId)
                    .setParameter(5, recentTopicMemberNickname)
                    .setParameter(6, LocalDateTime.now())
                    .setParameter(7, boardId)
                    .executeUpdate();
            return affect == 1 ? Optional.of(true) : Optional.empty();
        } catch (Exception e) {
            if(logger.isDebugEnabled()){
                logger.debug(e.getMessage(), e);
            }
            return Optional.empty();
        }
    }
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public Optional<Boolean> updatePosts(long boardId) {
        try {
            int affect = entityManager.createQuery("UPDATE BoardStats bs SET bs.postses = bs.postses + 1, bs.updateDate = ?1 WHERE bs.boardId = ?2")
                    .setParameter(1, LocalDateTime.now())
                    .setParameter(2, boardId)
                    .executeUpdate();
            return affect == 1 ? Optional.of(true) : Optional.empty();
        } catch (Exception e) {
            if(logger.isDebugEnabled()){
                logger.debug(e.getMessage(), e);
            }
            return Optional.empty();
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void plusFavorites(long boardId)throws IllegalStateException {
        int affect = entityManager
                    .createQuery("UPDATE BoardStats bs SET bs.favorites = bs.favorites + 1, bs.updateDate = ?1 WHERE bs.boardId = ?2")
                    .setParameter(1, LocalDateTime.now())
                    .setParameter(2, boardId)
                    .executeUpdate();
        if(affect != 1){
            throw new IllegalStateException("[plus]更新版块收藏统计失败");
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void negateFavorites(long boardId)throws IllegalStateException {
        int affect = entityManager
                    .createQuery("UPDATE BoardStats bs SET bs.favorites = bs.favorites - 1, bs.updateDate = ?1 WHERE bs.boardId = ?2")
                    .setParameter(1, LocalDateTime.now())
                    .setParameter(2, boardId)
                    .executeUpdate();
        if(affect != 1){
            throw new IllegalStateException("[negate]更新版块收藏统计失败");
        }
    }
    
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void balanceTopicPosts(long plusBoardId, long minusBoardId, long postsSize)throws IllegalStateException {
        logger.error("[MTV][12]新版块[+1]: " + plusBoardId + ", 原版块[-1]: " + minusBoardId + ", 回复的数量: " + postsSize);
        //原版块话题-1,新版块话题+1
        //原版块回复-d.successValue,新版块回复+d.successValue
        try {
            entityManager.createQuery("UPDATE BoardStats bs SET bs.topices = bs.topices - ?1, bs.postses = bs.postses - ?2 WHERE bs.boardId = ?3")
                    .setParameter(1, 1)
                    .setParameter(2, postsSize)
                    .setParameter(3, minusBoardId)
                    .executeUpdate();
        } catch (Exception e) {
            logger.error("[MTV][13]原版块[-1]: " + minusBoardId + ", 平衡失败: " + e.getMessage());
            throw new IllegalStateException("更新原版块话题数量失败, 异常: " + e.getMessage());
        }
        try {
            entityManager.createQuery("UPDATE BoardStats bs SET bs.topices = bs.topices + ?1, bs.postses = bs.postses + ?2 WHERE bs.boardId = ?3")
                    .setParameter(1, 1)
                    .setParameter(2, postsSize)
                    .setParameter(3, plusBoardId)
                    .executeUpdate();
        } catch (Exception e) {
            logger.error("[MTV][14]新版块[+1]: " + plusBoardId + ", 平衡失败: " + e.getMessage());
            throw new IllegalStateException("更新目标版块话题数量失败, 异常: " + e.getMessage());
        }
    }
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void balanceTopic(long plusBoardId, long minusBoardId)throws IllegalStateException {
        //原版块话题-1,新版块话题+1
        //原版块回复-d.successValue,新版块回复+d.successValue
        try {
            entityManager.createQuery("UPDATE BoardStats bs SET bs.topices = bs.topices - ?1 WHERE bs.boardId = ?2")
                    .setParameter(1, 1)
                    .setParameter(2, minusBoardId)
                    .executeUpdate();
        } catch (Exception e) {
            logger.error("[MTV][13]原版块[-1]: " + minusBoardId + ", 平衡失败: " + e.getMessage());
            throw new IllegalStateException("更新原版块话题数量失败, 异常: " + e.getMessage());
        }
        try {
            entityManager.createQuery("UPDATE BoardStats bs SET bs.topices = bs.topices + ?1 WHERE bs.boardId = ?2")
                    .setParameter(1, 1)
                    .setParameter(2, plusBoardId)
                    .executeUpdate();
        } catch (Exception e) {
            logger.error("[MTV][14]新版块[+1]: " + plusBoardId + ", 平衡失败: " + e.getMessage());
            throw new IllegalStateException("更新目标版块话题数量失败, 异常: " + e.getMessage());
        }
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public Optional<Boolean> updateTopices(long boardId) {
        try {
            entityManager.createQuery("UPDATE BoardStats bs SET bs.topices = bs.topices + ?1 WHERE bs.boardId = ?2")
                    .setParameter(1, 1)
                    .setParameter(2, boardId)
                    .executeUpdate();
            return Optional.of(true);
        } catch (Exception e) {
            if(logger.isDebugEnabled()){
                logger.debug(e.getMessage(), e);
            }
            return Optional.empty();
        }
    }
    
    @Override
    public Stream<BoardStats> findAllByBoardId(Collection<Long> boardIdList) {
        if (boardIdList == null || boardIdList.isEmpty()) {
            return Stream.empty();
        }
        return entityManager.createQuery("SELECT bs FROM BoardStats bs WHERE bs.boardId IN ?1", BoardStats.class).setParameter(1, boardIdList).getResultStream();
    }
    
    @Override
    public Stream<BoardStats> findAllByBoardGroup(int volumesId) {
        return entityManager.createQuery("SELECT bs FROM BoardStats bs WHERE bs.volumesId = ?1", BoardStats.class).setParameter(1, volumesId).getResultStream();
    }
    /**
     * [NativeSQL]
     * @return 
     */
    @Override
    @SuppressWarnings("unchecked")
    public Stream<BoardStats> findAllForNotOriginBoard() {
        final String SQL = "SELECT bs.* FROM apo_board_stats AS bs JOIN apo_board AS b ON bs.BOARDID = b.ID WHERE b.ORIGIN = ?1";
        return entityManager.createNativeQuery(SQL, BoardStats.class).setParameter(1, false).getResultStream();
    }
    
    @Override
    public Optional<BoardStats> findOneByBoard(long boardId) {
        try {
            BoardStats bs = entityManager.createQuery("SELECT bs FROM BoardStats bs WHERE bs.boardId = ?1", BoardStats.class).setParameter(1, boardId).getSingleResult();
            return Optional.ofNullable(bs);
        } catch (javax.persistence.NoResultException e) {
            if(logger.isDebugEnabled()){
                logger.debug(e.getMessage(), e);
            }
            return Optional.empty();
        }
    }
    /**
     * [NativeSQL]
     * @return 
     */
    @Override
    public Map<ForumActionEnum, Long> sumTopicAndPosts() {
        final String SQL = "SELECT SUM(TOPICES), SUM(POSTSES) FROM apo_board_stats";
        @SuppressWarnings("unchecked")
        List<Object[]> result = entityManager.createNativeQuery(SQL).getResultList();
        if(null == result || result.isEmpty()){
            return Collections.emptyMap();
        }
        //
        Map<ForumActionEnum, Long> data = new HashMap<>();
        for (Object[] columns : result) {
            Long ts;
            try {
                ts = ((BigDecimal) columns[0]).longValue();
            } catch (ClassCastException e) {
                ts = (Long) columns[0];
            } catch(NullPointerException e1){
                ts = 0L;
            }
            Long ps;
            try {
                ps = ((BigDecimal) columns[1]).longValue();
            } catch (ClassCastException e) {
                ps = (Long) columns[1];
            } catch(NullPointerException e1){
                ps = 0L;
            }
            
            data.put(ForumActionEnum.TOPIC_PUBLISH, ts);
            data.put(ForumActionEnum.POSTS_REPLY, ps);
        }
        return data;
    }
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void save(BoardStats entity) {
        entityManager.persist(entity);
    }
    
    @Override
    public Optional<BoardStats> findOne(Long primaryKey) {
        return Optional.empty();
    }
    
    @Override
    public Optional<Boolean> edit(BoardStats updateEntity) {
        return Optional.empty();
    }
    
    @Override
    public Stream<BoardStats> findAll() {
        return entityManager.createQuery("SELECT bs FROM BoardStats bs", BoardStats.class).getResultStream();
    }
    
    @Override
    public long count() {
        return -1L;
    }
}